﻿
// ServDoc.cpp: CServDoc 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "Serv.h"
#endif

#include "ServDoc.h"

#include <propkey.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CServDoc

IMPLEMENT_DYNCREATE(CServDoc, CDocument)

BEGIN_MESSAGE_MAP(CServDoc, CDocument)
    ON_COMMAND(ID_FILE_UPDATE, &CServDoc::OnFileUpdate)
    ON_UPDATE_COMMAND_UI(ID_FILE_UPDATE, &CServDoc::OnUpdateFileUpdate)
    ON_COMMAND(ID_OBJECT_EDIT, &CServDoc::OnObjectEdit)
END_MESSAGE_MAP()

BEGIN_DISPATCH_MAP(CServDoc, CDocument)
END_DISPATCH_MAP()

// 注意: 我们添加了对 IID_IServ 的支持来支持类型安全绑定
//  以支持来自 VBA 的类型安全绑定。  此 IID 必须同附加到 .IDL 文件中的
//  调度接口的 GUID 匹配。

// {6f75df0b-a33e-415a-be97-6af4f909e4cf}
static const IID IID_IServ =
{0x6f75df0b,0xa33e,0x415a,{0xbe,0x97,0x6a,0xf4,0xf9,0x09,0xe4,0xcf}};

BEGIN_INTERFACE_MAP(CServDoc, CDocument)
	INTERFACE_PART(CServDoc, IID_IServ, Dispatch)
	INTERFACE_PART(CServDoc, IID_IOleObject, OleObject)
	INTERFACE_PART(CServDoc, IID_IDataObject, DataObject)
	INTERFACE_PART(CServDoc, IID_IPersistStorage, PersistStorage)
END_INTERFACE_MAP()


// CServDoc 构造/析构

CServDoc::CServDoc() noexcept
{
    // TODO: 在此添加一次性构造代码

    EnableAutomation();
    m_lpClientSite = NULL;
    m_lpOleAdviseHolder = NULL;
    m_lpDataAdviseHolder = NULL;
    AfxOleLockApp();
}

CServDoc::~CServDoc()
{
	AfxOleUnlockApp();
}

BOOL CServDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: 在此添加重新初始化代码
	// (SDI 文档将重用该文档)

    m_strText = _T("Default text");

	return TRUE;
}

// CServDoc 序列化

void CServDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: 在此添加存储代码
	}
	else
	{
		// TODO: 在此添加加载代码
	}
}

#ifdef SHARED_HANDLERS

// 缩略图的支持
void CServDoc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)
{
	// 修改此代码以绘制文档数据
	dc.FillSolidRect(lprcBounds, RGB(255, 255, 255));

	CString strText = _T("TODO: implement thumbnail drawing here");
	LOGFONT lf;

	CFont* pDefaultGUIFont = CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT));
	pDefaultGUIFont->GetLogFont(&lf);
	lf.lfHeight = 36;

	CFont fontDraw;
	fontDraw.CreateFontIndirect(&lf);

	CFont* pOldFont = dc.SelectObject(&fontDraw);
	dc.DrawText(strText, lprcBounds, DT_CENTER | DT_WORDBREAK);
	dc.SelectObject(pOldFont);
}

// 搜索处理程序的支持
void CServDoc::InitializeSearchContent()
{
	CString strSearchContent;
	// 从文档数据设置搜索内容。
	// 内容部分应由“;”分隔

	// 例如:     strSearchContent = _T("point;rectangle;circle;ole object;")；
	SetSearchContent(strSearchContent);
}

void CServDoc::SetSearchContent(const CString& value)
{
	if (value.IsEmpty())
	{
		RemoveChunk(PKEY_Search_Contents.fmtid, PKEY_Search_Contents.pid);
	}
	else
	{
		CMFCFilterChunkValueImpl *pChunk = nullptr;
		ATLTRY(pChunk = new CMFCFilterChunkValueImpl);
		if (pChunk != nullptr)
		{
			pChunk->SetTextValue(PKEY_Search_Contents, value, CHUNK_TEXT);
			SetChunkValue(pChunk);
		}
	}
}

#endif // SHARED_HANDLERS

// CServDoc 诊断

#ifdef _DEBUG
void CServDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CServDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG


STDMETHODIMP_(ULONG) CServDoc::XOleObject::AddRef()
{
    TRACE("CServDoc::XOleObject::AddRef\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    return pThis->InternalAddRef();
}

STDMETHODIMP_(ULONG) CServDoc::XOleObject::Release()
{
    TRACE("CServDoc::XOleObject::Release\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    return pThis->InternalRelease();
}

STDMETHODIMP CServDoc::XOleObject::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
    TRACE("CServDoc::XOleObject::QueryInterface\r\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    return pThis->InternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP CServDoc::XOleObject::SetClientSite(LPOLECLIENTSITE pClientSite)
{
    TRACE("CServDoc::XOleObject::SetClientSite\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    if (pClientSite != NULL)
        pClientSite->AddRef();
    if (pThis->m_lpClientSite != NULL) pThis->m_lpClientSite->Release();
    pThis->m_lpClientSite = pClientSite;

    return NOERROR;
}

STDMETHODIMP CServDoc::XOleObject::GetClientSite(LPOLECLIENTSITE* ppClientSite)
{
    TRACE("CServDoc::XOleObject::GetClientSite\n");
    METHOD_PROLOGUE(CServDoc, OleObject);

    *ppClientSite = pThis->m_lpClientSite;
    if (pThis->m_lpClientSite != NULL)
        pThis->m_lpClientSite->AddRef();
    return NOERROR;
}

STDMETHODIMP CServDoc::XOleObject::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
{
    TRACE("CServDoc::XOleObject::SetHostNames\n");
    METHOD_PROLOGUE(CServDoc, OleObject);

    CString strTitle = _T("EX28C object embedded in ");
    if (szContainerApp != NULL) {
        strTitle += CString(szContainerApp);
    }
    CWnd* pWnd = AfxGetMainWnd();
    pWnd->SetWindowText(strTitle);

    return NOERROR;
}

STDMETHODIMP CServDoc::XOleObject::Close(DWORD dwSaveOption)
{
    TRACE("CServDoc::XOleObject::Close\n");
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
{
    TRACE("CServDoc::XOleObject::SetMoniker\n");
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker)
{
    TRACE("CServDoc::XOleObject::GetMoniker\n");
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::InitFromData(LPDATAOBJECT pDataObject, BOOL fCreation, DWORD dwReserved)
{
    TRACE("CServDoc::XOleObject::InitFromData\n");
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::GetClipboardData(DWORD dwReserved, LPDATAOBJECT* ppDataObject)
{
    TRACE("CServDoc::XOleObject::GetClipboardData\n");
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::DoVerb(
    LONG iVerb,
    LPMSG lpmsg,
    LPOLECLIENTSITE pActiveSite,
    LONG lindex,
    HWND hwndParent,
    LPCRECT lpPosRect
)
{
    TRACE("CServDoc::XOleObject::DoVerb - %d\n", iVerb);
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);

    pThis->InternalAddRef();
    CWnd* pWnd = AfxGetMainWnd();
    switch (iVerb)
    {
    case OLEIVERB_OPEN:
    case -OLEIVERB_OPEN - 1:
    case OLEIVERB_PRIMARY:
    case OLEIVERB_SHOW:
        pWnd->ShowWindow(SW_SHOW);
        pWnd->SetActiveWindow();
        pWnd->SetForegroundWindow();
        break;

    case OLEIVERB_HIDE:
    case -OLEIVERB_HIDE - 1:
        return E_NOTIMPL;

    default:
        if (iVerb < 0)
            return E_NOTIMPL;

        AfxThrowOleException(OLEOBJ_S_INVALIDVERB);
    }
    pThis->InternalRelease();
    pThis->m_lpClientSite->OnShowWindow(TRUE);

    return NOERROR;
}

STDMETHODIMP CServDoc::XOleObject::EnumVerbs(IEnumOLEVERB** ppenumOleVerb)
{
    TRACE("CServDoc::XOleObject::EnumVerbs\n");
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::Update()
{
    TRACE("CServDoc::XOleObject::Update\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::IsUpToDate()
{
    TRACE("CServDoc::XOleObject::IsUpToDate\n");
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::GetUserClassID(CLSID* pClsid)
{
    TRACE("CServDoc::XOleObject::GetUserClassID\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);

    return pThis->m_xPersistStorage.GetClassID(pClsid);
}

STDMETHODIMP CServDoc::XOleObject::GetUserType(DWORD dwFormOfType, LPOLESTR* ppszUserType)
{
    TRACE("CServDoc::XOleObject::GetUserType\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);

    *ppszUserType = NULL;

    CLSID clsid;
    pThis->m_xOleObject.GetUserClassID(&clsid);
    return OleRegGetUserType(clsid, dwFormOfType, ppszUserType);
}

STDMETHODIMP CServDoc::XOleObject::SetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
{
    TRACE("CServDoc::XOleObject::SetExtent\n");
    return E_FAIL;
}

STDMETHODIMP CServDoc::XOleObject::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
{
    TRACE("CServDoc::XOleObject::GetExtent\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::Advise(IAdviseSink* pAdvSink, DWORD* pdwConnection)
{
    TRACE("CServDoc::XOleObject::Advise\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);
    *pdwConnection = 0;
    if (pThis->m_lpOleAdviseHolder == NULL &&
        ::CreateOleAdviseHolder(&pThis->m_lpOleAdviseHolder) != NOERROR) {
        return E_OUTOFMEMORY;
    }
    ASSERT(pThis->m_lpOleAdviseHolder != NULL);
    return pThis->m_lpOleAdviseHolder->Advise(pAdvSink, pdwConnection);
}

STDMETHODIMP CServDoc::XOleObject::Unadvise(DWORD dwConnection)
{
    TRACE("CServDoc::XOleObject::Unadvise\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::EnumAdvise(LPENUMSTATDATA* ppenumAdvise)
{
    TRACE("CServDoc::XOleObject::EnumAdvise\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XOleObject::GetMiscStatus(DWORD dwAspect, DWORD* pdwStatus)
{
    TRACE("CServDoc::XOleObject::GetMiscStatus\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);

    *pdwStatus = 0;

    CLSID clsid;
    pThis->m_xOleObject.GetUserClassID(&clsid);
    return OleRegGetMiscStatus(clsid, dwAspect, pdwStatus);
}

STDMETHODIMP CServDoc::XOleObject::SetColorScheme(LPLOGPALETTE lpLogpal)
{
    TRACE("CServDoc::XOleObject::SetColorScheme\n");
    METHOD_PROLOGUE(CServDoc, OleObject);
    ASSERT_VALID(pThis);

    return E_NOTIMPL;
}

STDMETHODIMP_(ULONG) CServDoc::XDataObject::AddRef()
{
    TRACE("CServDoc::XDataObject::AddRef\n");
    METHOD_PROLOGUE(CServDoc, DataObject);
    return pThis->InternalAddRef();
}

STDMETHODIMP_(ULONG) CServDoc::XDataObject::Release()
{
    TRACE("CServDoc::XDataObject::Release\n");
    METHOD_PROLOGUE(CServDoc, DataObject);
    return pThis->InternalRelease();
}

STDMETHODIMP CServDoc::XDataObject::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
    TRACE("CServDoc::XDataObject::QueryInterface");
    METHOD_PROLOGUE(CServDoc, DataObject);
    return pThis->InternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP CServDoc::XDataObject::GetData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
    TRACE("CServDoc::XDataObject::GetData -- %d\n", lpFormatEtc->cfFormat);
    METHOD_PROLOGUE(CServDoc, DataObject);
    ASSERT_VALID(pThis);

    if (lpFormatEtc->cfFormat != CF_METAFILEPICT) {
        return S_FALSE;
    }
    HGLOBAL hPict = pThis->MakeMetaFile();
    lpStgMedium->tymed = TYMED_MFPICT;
    lpStgMedium->hMetaFilePict = hPict;
    lpStgMedium->pUnkForRelease = NULL;
    return S_OK;
}

STDMETHODIMP CServDoc::XDataObject::GetDataHere(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
    TRACE("CServDoc::XDataObject::GetDataHere\n");
    METHOD_PROLOGUE(CServDoc, DataObject);
    ASSERT_VALID(pThis);
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XDataObject::QueryGetData(LPFORMATETC lpFormatEtc)
{
    TRACE("CServDoc::XDataObject::QueryGetData -- %d\n", lpFormatEtc->cfFormat);
    METHOD_PROLOGUE(CServDoc, DataObject);
    ASSERT_VALID(pThis);
    if (lpFormatEtc->cfFormat != CF_METAFILEPICT) {
        return S_FALSE;
    }
    return S_OK;
}

STDMETHODIMP CServDoc::XDataObject::GetCanonicalFormatEtc(LPFORMATETC lpFormatEtcIn, LPFORMATETC lpFormatEtcOut)
{
    TRACE("CServDoc::XDataObject::GetCanonicalFormatEtc\n");
    return DATA_S_SAMEFORMATETC;
}

STDMETHODIMP CServDoc::XDataObject::SetData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, BOOL bRelease)
{
    TRACE("CServDoc::XDataObject::SetData\n");
    METHOD_PROLOGUE(CServDoc, DataObject);
    ASSERT_VALID(pThis);
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC* ppenumFormatEtc)
{
    TRACE("CServDoc::XDataObject::EnumFormatEtc\n");
    METHOD_PROLOGUE(CServDoc, DataObject);
    ASSERT_VALID(pThis);
    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XDataObject::DAdvise(
    FORMATETC* pFormatEtc,
    DWORD advf,
    LPADVISESINK pAdvSink,
    DWORD* pdwConnection
)
{
    TRACE("CServDoc::XDataObject::DAdvise\n");
    METHOD_PROLOGUE(CServDoc, DataObject);
    ASSERT_VALID(pThis);

    *pdwConnection = 555;
    if (pThis->m_lpDataAdviseHolder == NULL &&
        CreateDataAdviseHolder(&pThis->m_lpDataAdviseHolder) != S_OK) {
        return E_OUTOFMEMORY;
    }
    ASSERT(pThis->m_lpDataAdviseHolder != NULL);
    HRESULT hr = pThis->m_lpDataAdviseHolder->Advise(this, pFormatEtc, advf, pAdvSink, pdwConnection);
    return hr;
}

STDMETHODIMP CServDoc::XDataObject::DUnadvise(DWORD dwConnection)
{
    TRACE("CServDoc::XDataObject::DUnadvise\n");
    METHOD_PROLOGUE(CServDoc, DataObject);
    ASSERT_VALID(pThis);

    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XDataObject::EnumDAdvise(LPENUMSTATDATA* ppenumAdvise)
{
    TRACE("CServDoc::XDataObject::EnumDAdvise\n");
    METHOD_PROLOGUE(CServDoc, DataObject);
    ASSERT_VALID(pThis);

    return E_NOTIMPL;
}

STDMETHODIMP_(ULONG) CServDoc::XPersistStorage::AddRef()
{
    TRACE("CServDoc::XPersistStorage:::AddRef\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    return pThis->InternalAddRef();
}

STDMETHODIMP_(ULONG) CServDoc::XPersistStorage::Release()
{
    TRACE("CServDoc::XPersistStorage::Release\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    return pThis->InternalRelease();
}

STDMETHODIMP CServDoc::XPersistStorage::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
    TRACE("CServDoc::XPersistStorage::QueryInterface");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    return pThis->InternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP CServDoc::XPersistStorage::GetClassID(LPCLSID lpClassID)
{
    TRACE("CServDoc::XPersistStorage::GetClassID\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    ASSERT_VALID(pThis);
    *lpClassID = clsid;
    return NOERROR;
}

STDMETHODIMP CServDoc::XPersistStorage::IsDirty()
{
    TRACE("CServDoc::XPersistStorage::IsDirty\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    ASSERT_VALID(pThis);

    return pThis->IsModified() ? NOERROR : S_FALSE;
}

STDMETHODIMP CServDoc::XPersistStorage::InitNew(LPSTORAGE pStg)
{
    TRACE("CServDoc::XPersistStorage::InitNew\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    ASSERT_VALID(pThis);
    ASSERT(pStg != NULL);

    pThis->SetModifiedFlag();
    pThis->SendInitialUpdate();
    return NOERROR;
}

STDMETHODIMP CServDoc::XPersistStorage::Load(LPSTORAGE pStgLoad)
{
    TRACE("CServDoc::XPersistStorage::Load\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    ASSERT_VALID(pThis);

    ASSERT(pStgLoad != NULL);
    LPSTREAM pStream;
    ULONG nBytesRead;
    char buffer[101];
    try {
        pThis->DeleteContents();
        if (pStgLoad->OpenStream(L"Ex28c Text", NULL,
            STGM_READ | STGM_SHARE_EXCLUSIVE,
            0, &pStream) == NOERROR) {
            pStream->Read(buffer, 100, &nBytesRead);
            pStream->Release();
            pThis->m_strText = buffer;
        }
    }
    catch (CException* pe) {
        pe->Delete();
        return E_FAIL;
    }

    pThis->SetModifiedFlag();
    pThis->SendInitialUpdate();
    return NOERROR;
}

STDMETHODIMP CServDoc::XPersistStorage::Save(LPSTORAGE pStgSave, BOOL fSameAsLoad)
{
    TRACE("CServDoc::XPersistStorage::Save\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    ASSERT_VALID(pThis);

    if (fSameAsLoad && !pThis->IsModified())
        return NOERROR;

    ASSERT(pStgSave != NULL);
    LPSTREAM pStream;
    ULONG nBytesWritten;
    try {
        if (pStgSave->CreateStream(L"Ex28c Text",
            STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
            0, 0, &pStream) == NOERROR) {
            pStream->Write((const wchar_t*)pThis->m_strText, pThis->m_strText.GetLength() + 1, &nBytesWritten);
            pStream->Release();
        }
        else return E_FAIL;
    }
    catch (CException* pe) {
        pe->Delete();
        return E_FAIL;
    }

    pThis->SetModifiedFlag();
    pThis->SendInitialUpdate();
    return NOERROR;
}

STDMETHODIMP CServDoc::XPersistStorage::SaveCompleted(LPSTORAGE pStgSaved)
{
    TRACE("CServDoc::XPersistStorage::SaveCompleted\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    ASSERT_VALID(pThis);

    return E_NOTIMPL;
}

STDMETHODIMP CServDoc::XPersistStorage::HandsOffStorage()
{
    TRACE("CServDoc::XPersistStorage::HandsOffStorage\n");
    METHOD_PROLOGUE(CServDoc, PersistStorage);
    ASSERT_VALID(pThis);

    return E_NOTIMPL;
}

HGLOBAL CServDoc::MakeMetaFile()
{
    HGLOBAL hPict;
    CMetaFileDC dcm;
    VERIFY(dcm.Create());
    CSize size(5000, 5000);
    dcm.SetMapMode(MM_ANISOTROPIC);
    dcm.SetWindowOrg(0, 0);
    dcm.SetWindowExt(size.cx, -size.cy);
    dcm.Rectangle(CRect(500, -1000, 1500, -2000));
    CFont font;
    font.CreateFont(-500, 0, 0, 0, 400, FALSE, FALSE, 0,
        ANSI_CHARSET, OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
        DEFAULT_PITCH | FF_SWISS, _T("Arial"));
    CFont* pFont = dcm.SelectObject(&font);
    dcm.TextOut(0, 0, m_strText);
    dcm.SelectObject(pFont);

    HMETAFILE hMF = dcm.Close();
    ASSERT(hMF != NULL);
    hPict = ::GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
    ASSERT(hPict != NULL);
    LPMETAFILEPICT lpPict;
    lpPict = (LPMETAFILEPICT) ::GlobalLock(hPict);
    ASSERT(lpPict != NULL);
    lpPict->mm = MM_ANISOTROPIC;
    lpPict->hMF = hMF;
    lpPict->xExt = size.cx;
    lpPict->yExt = size.cy;
    ::GlobalUnlock(hPict);
    return hPict;
}

void CServDoc::OnFileUpdate()
{
    if (m_lpClientSite == NULL) return;
    VERIFY(m_lpClientSite->SaveObject() == NOERROR);
    if (m_lpOleAdviseHolder != NULL)
        m_lpOleAdviseHolder->SendOnSave();
    SetModifiedFlag(FALSE);
}

void CServDoc::OnUpdateFileUpdate(CCmdUI* pCmdUI)
{
    pCmdUI->Enable(IsModified());
}

void CServDoc::OnObjectEdit()
{
    CEditDialog dlg;
    dlg.m_strText = m_strText;
    if (dlg.DoModal() == IDOK)
    {
        m_strText = dlg.m_strText;
        UpdateAllViews(NULL);
        LPDATAOBJECT lpDataObject = (LPDATAOBJECT)GetInterface(&IID_IDataObject);
        HRESULT hr = m_lpDataAdviseHolder->SendOnDataChange(lpDataObject, 0, NULL);
        ASSERT(hr == NOERROR);
        SetModifiedFlag();
    }
}

void CServDoc::OnCloseDocument()
{
    InternalAddRef();

    if (m_lpClientSite != NULL) {
        m_lpClientSite->OnShowWindow(FALSE);
        m_lpClientSite->Release();
    }

    if (m_lpOleAdviseHolder != NULL)
        m_lpOleAdviseHolder->SendOnClose();

    BOOL bAutoDelete = m_bAutoDelete;
    m_bAutoDelete = FALSE;
    CDocument::OnCloseDocument();

    LPUNKNOWN lpUnknown = (LPUNKNOWN)GetInterface(&IID_IUnknown);
    ASSERT(lpUnknown != NULL);
    CoDisconnectObject(lpUnknown, 0);

    if (m_lpOleAdviseHolder != NULL)
        m_lpOleAdviseHolder->Release();

    if (m_lpDataAdviseHolder != NULL)
        m_lpDataAdviseHolder->Release();

    m_lpClientSite = NULL;
    m_lpOleAdviseHolder = NULL;
    m_lpDataAdviseHolder = NULL;

    InterlockedDecrement(&m_dwRef);
    if (bAutoDelete) {
        delete this;
    }
}
